package cn.jtcoding.common.framework.utils;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @Author jason.tang
 * @Date 2020/8/27 13:45
 * @Desc 函数式编程语法工具类
 */

public final class FunctionUtils {

    /**
     * 快速映射集合
     * @param collection 源集合
     * @param mapper 映射函数
     * @param <T> 源对象类型
     * @param <R> 目标对象类型
     * @return 结果集合
     */
    public static <T, R> List<R> map(Collection<T> collection, Function<T, R> mapper) {
        return collection.stream().map(mapper).distinct().collect(toList());
    }

    /**
     * 根据自定义条件过滤出对象
     * @param collection 集合
     * @param <R> 目标对象类型
     * @return 目标对象
     */
    public static <R> Function<Predicate<R>, Optional<R>> filterOutObject(Collection<R> collection) {
        return predicate -> collection.stream().filter(predicate).findFirst();
    }

    /**
     * 根据自定义条件过滤出集合
     * @param collection 源集合
     * @param <R> 目标对象类型
     * @return 目标对象集合
     */
    public static <R> Function<Predicate<R>, Collection<R>> filterOutCollection(Collection<R> collection) {
        return predicate -> collection.stream().filter(predicate).collect(toList());
    }

    /**
     * 任何一个元素匹配
     * @param collection
     * @param <R>
     * @return
     */
    public static <R> Function<Predicate<R>, Boolean> anyMatch(Collection<R> collection) {
        return predicate -> collection.parallelStream().anyMatch(predicate);
    }

    /**
     * 一个元素也没有匹配
     * @param collection
     * @param <R>
     * @return
     */
    public static <R> Function<Predicate<R>, Boolean> noneMatch(Collection<R> collection) {
        return predicate -> collection.parallelStream().noneMatch(predicate);
    }

    /**
     * 所有元素匹配
     * @param collection
     * @param <R>
     * @return
     */
    public static <R> Function<Predicate<R>, Boolean> allMatch(Collection<R> collection) {
        return predicate -> collection.parallelStream().allMatch(predicate);
    }


    /**
     * 分组
     * @param collection 集合
     * @param mapper 映射函数
     * @param <E> 集合元素类型
     * @param <K> 目标map key类型
     * @return 集合
     */
    public static <E, K> Map<K, List<E>> groupBy(Collection<E> collection, Function<E, K> mapper) {
        return collection.stream().collect(Collectors.groupingBy(mapper));
    }

    /**
     * map排序
     * @param map 集合
     * @param <K> 目标map key类型
     * @param <V> 目标map value类型
     * @return 有序集合
     */
    public static <K, V> LinkedHashMap<K, V> sortMap(Map<K, V> map) {
        return map.entrySet()
                .stream()
                .sorted(Map.Entry.comparingByKey(Comparator.comparing(Object::toString)))
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        right(),
                        LinkedHashMap::new));

    }

    /**
     * list 转 有序map
     * @param collection 集合
     * @param mapper 映射函数
     * @param <E> 数据源集合
     * @param <K> key
     * @return 有序map
     */
    public static <E, K> LinkedHashMap<K, List<E>> sortMap(Collection<E> collection, Function<E, K> mapper) {
        return sortMap(groupBy(collection, mapper));
    }

    /**
     * 集合合并处理
     * @param collections
     * @param <R>
     * @return
     */
    public static <R> List<R> flatMap(Collection<Collection<R>> collections) {
        return collections.stream().flatMap(Collection::stream).collect(toList());
    }

    /**
     * 对集合进行单个或多个属性去重
     * @param collection
     * @param mapper
     * @param <R>
     * @return
     */
    public static <R> List<R> distinct(Collection<R> collection, Function<R, String> mapper) {
        return collection.stream()
                .collect(Collectors
                        .collectingAndThen(Collectors.toCollection(() -> new TreeSet<R>(Comparator.comparing(mapper))), ArrayList::new));
    }

    /**
     * 某一个 Long 类型字段的值总和
     * @param collection
     * @param <R>
     * @return
     */
    public static <R> Function<ToLongFunction<R>, Long> sumToLong(Collection<R> collection) {
        return function -> collection.stream().mapToLong(function).sum();
    }

    /**
     * 某一个 Double 字段的值总和
     * @param collection
     * @param <R>
     * @return
     */
    public static <R> Function<ToDoubleFunction<R>, Double> sumToDouble(Collection<R> collection) {
        return function -> collection.stream().mapToDouble(function).sum();
    }

    /**
     * 某一个 Integer 字段的值总和
     * @param collection
     * @param <R>
     * @return
     */
    public static <R> Function<ToIntFunction<R>, Integer> sumToInt(Collection<R> collection) {
        return function -> collection.stream().mapToInt(function).sum();
    }

    /**
     * 取左边
     * @param <T> 元素类型
     * @return 左边值
     */
    public static <T> BinaryOperator<T> left() {
        return (l, r) -> l;
    }

    /**
     * 取右边
     * @param <T> 元素类型
     * @return 右边值
     */
    public static <T> BinaryOperator<T> right() {
        return (l, r) -> r;
    }

}
